/*
 * Copyright (c) 2006-2025, RT-Thread Development Team
 *
 * SPDX-License-Identifier: Apache-2.0
 *
 * Change Logs:
 * Date           Author       Notes
 * 2025-10-14     RT-Thread    ds3231 sample
 */

#include <rtthread.h>
#include <rtdevice.h>
#include <board.h>

#include <stdlib.h>

#include "drv_ds3231.h"

#define DBG_TAG "ds3231.sample"
#define DBG_LVL DBG_INFO
#include <rtdbg.h>

#define DS3231_THREAD_PRIORITY     16
#define DS3231_THREAD_STACK_SIZE   1024
#define DS3231_THREAD_TIMESLICE    5

static ds3231_device_t ds3231_dev = RT_NULL;
static rt_thread_t ds3231_thread = RT_NULL;

static const char *week_days[] = 
{
    "Sunday",
    "Monday",
    "Tuesday",
    "Wednesday",
    "Thursday",
    "Friday",
    "Saturday"
};

static void ds3231_thread_entry(void *parameter)
{
    struct ds3231_time time;
    rt_err_t result;

    ds3231_dev = ds3231_init(DS3231_I2C_BUS_NAME);
    if (ds3231_dev == RT_NULL)
    {
        LOG_E("DS3231 init failed");
        return;
    }

    LOG_I("DS3231 initialized, syncing RTC to system time every 5 minutes");

    while (1)
    {
        result = ds3231_read_time(ds3231_dev, &time);
        if (result == RT_EOK)
        {
            time_t timestamp;
            struct tm tm_time;

            tm_time.tm_year = time.year + 100;
            tm_time.tm_mon = time.month - 1;
            tm_time.tm_mday = time.date;
            tm_time.tm_hour = time.hour;
            tm_time.tm_min = time.minute;
            tm_time.tm_sec = time.second;
            tm_time.tm_isdst = -1;

            timestamp = mktime(&tm_time);
            if (timestamp != -1)
            {
                set_timestamp(timestamp);
                LOG_D("System time synced from DS3231: 20%02d-%02d-%02d %02d:%02d:%02d",
                      time.year, time.month, time.date,
                      time.hour, time.minute, time.second);
            }
            else
            {
                LOG_W("Failed to convert DS3231 time to timestamp");
            }
        }
        else
        {
            LOG_E("Read DS3231 time failed");
        }

        rt_thread_mdelay(5 * 60 * 1000);
    }
}

int ds3231_sample_init(void)
{
    ds3231_thread = rt_thread_create("ds3231",
                                      ds3231_thread_entry,
                                      RT_NULL,
                                      DS3231_THREAD_STACK_SIZE,
                                      DS3231_THREAD_PRIORITY,
                                      DS3231_THREAD_TIMESLICE);

    if (ds3231_thread != RT_NULL)
    {
        rt_thread_startup(ds3231_thread);
    }
    else
    {
        LOG_E("Create ds3231 thread failed");
        return -RT_ERROR;
    }

    return RT_EOK;
}

INIT_APP_EXPORT(ds3231_sample_init);

static int get_ds3231_time(int argc, char **argv)
{
    struct ds3231_time time;
    
    if (ds3231_dev == RT_NULL)
    {
        rt_kprintf("DS3231 device not initialized\n");
        return -RT_ERROR;
    }
    
    if (ds3231_read_time(ds3231_dev, &time) == RT_EOK)
    {
        rt_kprintf("DS3231 Time: 20%02d-%02d-%02d %s %02d:%02d:%02d\n",
                   time.year, time.month, time.date,
                   week_days[time.day % 7],
                   time.hour, time.minute, time.second);
        return RT_EOK;
    }
    else
    {
        rt_kprintf("Read DS3231 time failed\n");
        return -RT_ERROR;
    }
}

static int get_ds3231_temp(int argc, char **argv)
{
    float temperature = 0.0;
    
    if (ds3231_dev == RT_NULL)
    {
        rt_kprintf("DS3231 device not initialized\n");
        return -RT_ERROR;
    }
    
    if (ds3231_read_temperature(ds3231_dev, &temperature) == RT_EOK)
    {
        rt_kprintf("DS3231 Temperature: %.2f C\n", temperature);
        return RT_EOK;
    }
    else
    {
        rt_kprintf("Read DS3231 temperature failed\n");
        return -RT_ERROR;
    }
}

static int set_ds3231_time(int argc, char **argv)
{
    struct ds3231_time time;
    
    if (argc != 8)
    {
        rt_kprintf("Usage: ds3231_set <year> <month> <date> <day> <hour> <minute> <second>\n");
        rt_kprintf("Example: ds3231_set 25 10 14 2 15 30 00\n");
        rt_kprintf("         (2025-10-14 Tuesday 15:30:00)\n");
        rt_kprintf("Day: 0=Sunday, 1=Monday, 2=Tuesday, 3=Wednesday, 4=Thursday, 5=Friday, 6=Saturday\n");
        return -RT_ERROR;
    }
    
    if (ds3231_dev == RT_NULL)
    {
        rt_kprintf("DS3231 device not initialized\n");
        return -RT_ERROR;
    }
    
    time.year = atoi(argv[1]);
    time.month = atoi(argv[2]);
    time.date = atoi(argv[3]);
    time.day = atoi(argv[4]);
    time.hour = atoi(argv[5]);
    time.minute = atoi(argv[6]);
    time.second = atoi(argv[7]);
    
    if (time.year > 99 || time.month > 12 || time.month < 1 || 
        time.date > 31 || time.date < 1 || time.day > 6 ||
        time.hour > 23 || time.minute > 59 || time.second > 59)
    {
        rt_kprintf("Invalid time parameters\n");
        return -RT_ERROR;
    }
    
    if (ds3231_write_time(ds3231_dev, &time) == RT_EOK)
    {
        rt_kprintf("Set time success: 20%02d-%02d-%02d %s %02d:%02d:%02d\n",
                   time.year, time.month, time.date,
                   week_days[time.day],
                   time.hour, time.minute, time.second);

        // 同步系统时间
        time_t timestamp;
        struct tm tm_time;
        tm_time.tm_year = time.year + 100;
        tm_time.tm_mon = time.month - 1;
        tm_time.tm_mday = time.date;
        tm_time.tm_hour = time.hour;
        tm_time.tm_min = time.minute;
        tm_time.tm_sec = time.second;
        tm_time.tm_isdst = -1;
        timestamp = mktime(&tm_time);
        if (timestamp != -1)
        {
            set_timestamp(timestamp);
            rt_kprintf("System time synced from DS3231\n");
        }
        else
        {
            rt_kprintf("Failed to convert DS3231 time to timestamp\n");
        }
        return RT_EOK;
    }
    else
    {
        rt_kprintf("Set time failed\n");
        return -RT_ERROR;
    }
}

MSH_CMD_EXPORT(get_ds3231_time, Get DS3231 RTC time);
MSH_CMD_EXPORT(get_ds3231_temp, Get DS3231 temperature);
MSH_CMD_EXPORT(set_ds3231_time, Set DS3231 RTC time);


